/*
 * Copyright 2020-2021 the original author or authors.
 *
 * Licensed under the General Public License, Version 3.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.gnu.org/licenses/gpl-3.0.en.html
 */

package team.seekers.oj.course.controller;

import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import team.seekers.oj.common.annotation.UserSession;
import team.seekers.oj.common.entity.ApiResponseBody;
import team.seekers.oj.common.entity.PageResult;
import team.seekers.oj.common.entity.UserSessionDTO;
import team.seekers.oj.common.enums.ApiExceptionEnum;
import team.seekers.oj.common.util.AssertUtils;
import team.seekers.oj.common.util.RedisUtils;
import team.seekers.oj.course.client.UserClient;
import team.seekers.oj.course.dao.CourseDao;
import team.seekers.oj.course.dto.CourseCreateReqDTO;
import team.seekers.oj.course.dto.CourseListDTO;
import team.seekers.oj.course.dto.CourseListReqDTO;
import team.seekers.oj.course.dto.CourseManageDTO;
import team.seekers.oj.course.entity.CourseDO;
import team.seekers.oj.course.entity.pa.LiveCodeJoinPA;
import team.seekers.oj.course.entity.pa.LiveCodeOutPA;
import team.seekers.oj.course.entity.vo.*;
import team.seekers.oj.course.enums.CourseStatusEnum;
import team.seekers.oj.course.sender.RabbitSender;
import team.seekers.oj.course.service.CourseLiveService;
import team.seekers.oj.course.service.CourseManageService;
import team.seekers.oj.course.service.CourseService;
import team.seekers.oj.lesson.dto.ChapterListDTO;
import team.seekers.oj.third.controller.EtherpadController;

import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

@Slf4j
@Controller
@RequestMapping("/course")
public class CourseController {

    @Autowired
    private CourseService courseService;

    @Autowired
    private CourseLiveService courseLiveService;

    @Autowired
    private CourseManageService courseManageService;

    @Autowired
    private CourseDao courseDao;

    @Autowired
    private EtherpadController etherpadController;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    RabbitSender rabbitSender;

    @Autowired
    private UserClient userClient;

    @PostMapping("/create")
    @ApiResponseBody
    public Long create(@RequestBody @Valid CourseCreateReqDTO reqDTO,
                       @UserSession UserSessionDTO userSessionDTO) {
        // 增补
        reqDTO.setUserId(userSessionDTO.getUserId());

//        List<Long> userIds = Optional.ofNullable(reqDTO.getUsers()).orElse(Lists.newArrayList());
//        reqDTO.setUsers(userIds.stream().distinct().collect(Collectors.toList()));

        return courseManageService.create(reqDTO);
    }

    @GetMapping("/info")
    @ApiResponseBody
    public CourseInfoVO info(@RequestParam long courseId) {
        CourseInfoVO courseInfoVO = courseService.getInfo(courseId);
        return courseInfoVO;
    }


    @GetMapping("/join")
    @ApiResponseBody
    public Void join(@RequestParam long courseId,
                     @RequestParam long groupId) {
        courseService.join(courseId,groupId);
        return null;
    }

    @GetMapping("/out")
    @ApiResponseBody
    public Void out(@RequestParam long courseId,
                    @RequestParam long groupId) {
        courseService.out(courseId,groupId);
        return null;
    }

    @GetMapping("/page")
    @ApiResponseBody
    public PageResult<CourseListDTO> page(CourseListReqDTO reqDTO,
                                          @UserSession(nullable=true) UserSessionDTO userSessionDTO) {
        if(userSessionDTO.getRoles().contains("user")){
            reqDTO.setStudentId(userSessionDTO.getUserId());
        }else if(userSessionDTO.getRoles().contains("admin")){
            reqDTO.setTeacherId(userSessionDTO.getUserId());
        }
        return courseService.page(reqDTO);
    }

    @GetMapping("/queryChaptersSections")
    @ApiResponseBody
    public List<ChapterListDTO> queryChaptersSections(@RequestParam Long courseId){
        return courseManageService.queryChaptersSections(courseId);
    }


    @PostMapping("/update")
    @ApiResponseBody
    public Void update(@RequestBody @Valid CourseManageDTO reqDTO,
                       @UserSession UserSessionDTO userSessionDTO) {
        // 超级管理员、创建者 可修改
        AssertUtils.isTrue(courseService.isCourseManager(reqDTO.getUserId(), userSessionDTO),
                ApiExceptionEnum.USER_NOT_MATCHING, "没有权限");

//        List<Long> users = Optional.ofNullable(reqDTO.getUsers()).orElse(Lists.newArrayList());
//        reqDTO.setUsers(users.stream().distinct().collect(Collectors.toList()));

        courseManageService.update(reqDTO);
        return null;
    }

    @GetMapping("/liveRecordInfo")
    @ApiResponseBody
    public CourseLiveRecordInfoVO liveRecordInfo(@RequestParam Long liveRecordId){
        CourseLiveRecordInfoVO liveRecord = courseLiveService.getRecordInfoById(liveRecordId);
        return liveRecord;
    }

    @GetMapping("/liveRecords")
    @ApiResponseBody
    public List<CourseLiveRecordListVO> liveRecords(@RequestParam Long courseId){
        CourseDO courseDO = courseDao.getById(courseId);
        AssertUtils.notNull(courseDO,
                ApiExceptionEnum.COURSE_NOT_FOUND, "课程不存在");
        // 创建直播并获取推流地址（同时创建协同白板）
        List<CourseLiveRecordListVO> liveRecords = courseLiveService.liveRecords(courseId);
        return liveRecords;
    }

    @GetMapping("/startLive")
    @ApiResponseBody
    public String startLive(@RequestParam Long courseId,
                            @RequestParam String title){
        CourseDO courseDO = courseDao.getById(courseId);
        AssertUtils.notNull(courseDO,
                ApiExceptionEnum.COURSE_NOT_FOUND, "课程不存在");
        // 创建直播并获取推流地址（同时创建协同白板）
        String pushUrl = courseLiveService.startLive(courseId,title);
        return pushUrl;
    }

    @GetMapping("/endLive")
    @ApiResponseBody
    public Void endLive(@RequestParam Long courseId){
        CourseDO courseDO = courseDao.getById(courseId);
        AssertUtils.notNull(courseDO,ApiExceptionEnum.COURSE_NOT_FOUND);
        courseLiveService.endLive(courseId);
        return null;
    }

    @GetMapping("/liveInfo")
    @ApiResponseBody
    public CourseLiveInfoVO liveAddress(@RequestParam Long courseId){
        CourseDO courseDO = courseDao.getById(courseId);
        AssertUtils.notNull(courseDO,
                ApiExceptionEnum.COURSE_NOT_FOUND);
        AssertUtils.isTrue((courseDO.getStatus().equals(CourseStatusEnum.TEACHING.getType())),
                ApiExceptionEnum.COURSE_NOT_FOUND);

        CourseLiveInfoVO courseLiveInfoVO = courseLiveService.liveInfo(courseId);
        return courseLiveInfoVO;
    }

    @GetMapping("/liveCode")
    @ApiResponseBody
    public String liveCode(@RequestParam Long courseLiveId){
        String content = etherpadController.content(courseLiveId.toString());
        return content;
    }

    /**
     * 学生进入直播
     */
    @GetMapping("/liveJoin")
    @ApiResponseBody
    public Void liveJoin(@RequestParam("liveId") long liveId,
                     @UserSession UserSessionDTO userSessionDTO) {
        Long userId = userSessionDTO.getUserId();
        String nickname = userClient.userIdToNickname(userId);
        String name = userSessionDTO.getNickname();
        redisUtils.sSet(liveId+"-watch",userId+"-"+nickname);
        return null;
    }

    /**
     * 学生退出直播
     */
    @GetMapping("/liveOut")
    @ApiResponseBody
    public Void liveOut(@RequestParam("liveId") long liveId,
                     @UserSession UserSessionDTO userSessionDTO) {
        Long userId = userSessionDTO.getUserId();
        String nickname = userClient.userIdToNickname(userId);
        redisUtils.setRemove(liveId+"-watch",userId+"-"+nickname);
        return null;
    }

    /**
     * 让学生可以上代码
     */
    @PostMapping("/liveCodeJoin")
    @ApiResponseBody
    public Void liveCodeJoin(@RequestBody LiveCodeJoinPA codeJoinPA) {
        Long userId = codeJoinPA.getUserId();
        String nickname = userClient.userIdToNickname(userId);
        redisUtils.sSet(codeJoinPA.getLiveId()+"-code",userId+"-"+nickname);
        return null;
    }

    /**
     * 让学生退出上代码
     */
    @GetMapping("/liveCodeOut")
    @ApiResponseBody
    public Void liveCodeOut(@RequestParam("userId") long userId,
                            @RequestParam("liveId") long liveId) {
        String nickname = userClient.userIdToNickname(userId);
        String msg = liveId + "-" + userId;
        rabbitSender.send("zzuoj.computer.department","chat",msg);
        redisUtils.setRemove(liveId+"-code",userId+"-"+nickname);
        return null;
    }

    /**
     * 检查自己是否可以协同编码
     */
    @GetMapping("/checkCodeAble")
    @ApiResponseBody
    public boolean checkCodeAble(@RequestParam("liveId") long liveId,
                              @UserSession UserSessionDTO userSessionDTO) {
        Long userId = userSessionDTO.getUserId();
        String nickname = userClient.userIdToNickname(userId);
        return redisUtils.sHasKey(liveId+"-code",userId+"-"+nickname);
    }

    /**
     * 当前直播中在线的用户
     */
    @GetMapping("/liveUsers")
    @ApiResponseBody
    public List<LiveUserListVO> liveUsers(@RequestParam("liveId") long liveId,
                                          @UserSession UserSessionDTO userSessionDTO) {
        Set<Object> objects = redisUtils.sGet(liveId + "-watch");
        ArrayList<LiveUserListVO> userListVOS = new ArrayList<>();
        for (Object object : objects) {
            LiveUserListVO liveUserListVO = new LiveUserListVO();
            String content = (String) object;
            String[] strings = content.split("-");
            liveUserListVO.setId(Long.parseLong(strings[0]));
            liveUserListVO.setName(strings[1]);
            userListVOS.add(liveUserListVO);
        }
        return userListVOS;
    }

    /**
     * 当前直播中可以协同编码的用户
     */
    @GetMapping("/liveCodeUsers")
    @ApiResponseBody
    public List<LiveUserListVO> liveCodeUsers(@RequestParam("liveId") long liveId,
                                          @UserSession UserSessionDTO userSessionDTO) {
        Set<Object> objects = redisUtils.sGet(liveId + "-code");
        ArrayList<LiveUserListVO> userListVOS = new ArrayList<>();
        for (Object object : objects) {
            LiveUserListVO liveUserListVO = new LiveUserListVO();
            String content = (String) object;
            String[] strings = content.split("-");
            liveUserListVO.setId(Long.parseLong(strings[0]));
            liveUserListVO.setName(strings[1]);
            userListVOS.add(liveUserListVO);
        }
        return userListVOS;
    }
}